package kpetruk.tanks2d.server;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;

import kpetruk.tanks2d.network.CommonNetwork;
import kpetruk.tanks2d.network.netobjects.ChatMessage;
import kpetruk.tanks2d.network.netobjects.RRBasicString;
import kpetruk.tanks2d.network.netobjects.RRPlayerName;
import kpetruk.tanks2d.network.netobjects.RequestResponce;
import kpetruk.tanks2d.network.netobjects.UnitList;
import kpetruk.tanks2d.server.data.GameMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;
import com.esotericsoftware.kryonet.FrameworkMessage.KeepAlive;

public class Tanks2dServer {
  private Server server = new Server();
  private Logger log = LoggerFactory.getLogger("kpetruk.tanks2d.server.GameServer");
  private CommonNetwork net = new CommonNetwork();
  private LinkedList<RequestResponce> inputQueue = new LinkedList<RequestResponce>();
  private LinkedList<RequestResponce> outputQueue = new LinkedList<RequestResponce>();
  private HashMap<Integer,GamePlayer> gamePlayers = new HashMap<Integer,GamePlayer>();
  
  private int maxPlayerID = 0;
  
  //map
  private GameMap map = new GameMap();
  
  
  public boolean init() {
    
    
    server.start();
    try {
      server.bind(CommonNetwork.tcpPort, CommonNetwork.udpPort);
    } catch (IOException e) {
      log.info("can't bind to port",e);
    }
    
    net.init(server);
    
    server.addListener(new Listener() {
      public void received (Connection connection, Object object) {
        if (object instanceof KeepAlive){
          //do nothing
          log.debug("keepalive");
        } else {
          ((RequestResponce) object).con = connection;
          inputQueue.add((RequestResponce) object);
          log.debug("server received msg from client."+connection.getID());
        }
      }
    });
    
    //init map
    //map.init();
    map.defaultInit();
    
    //add bots
    
    return true;
  }
  
  public void handleClientRequests() {
    //define limited amount of time to process input
    //Time t = ...
    //TODO replace true to t.delta < limited
    while (true && !inputQueue.isEmpty()) {
      log.debug("server RR size is "+inputQueue.size());
      
      Object cr = inputQueue.poll(); //TODO change method
      
      if (cr instanceof RRBasicString) {
        RRBasicString request = (RRBasicString)cr;
        log.info(request.text);
        RRBasicString response = new RRBasicString();
         response.text = "Thanks!";
         request.con.sendTCP(response);
      } else if (cr instanceof ChatMessage) {
        ChatMessage chatMessage = (ChatMessage)cr;
        //send message to all clients
        int id = chatMessage.con.getID();
        String playerNick = gamePlayers.get(id).nick;
        //add to output queue
        for (GamePlayer player : gamePlayers.values()) {
          ChatMessage response = new ChatMessage();
          response.message = playerNick+":"+chatMessage.message;
          player.con.sendTCP(response);
        }
      } else if (cr instanceof RRPlayerName) {
        //new player connection request
        RRPlayerName nickRequest = (RRPlayerName)cr;
        log.info("[nick conected]"+nickRequest.con.getID()+":"+nickRequest.name);
        maxPlayerID++;
        GamePlayer player = new GamePlayer();
        player.nick = nickRequest.name;
        player.con = nickRequest.con;
        gamePlayers.put(maxPlayerID,player);
        log.info("player ["+player.nick+"]["+player.con.getID()+"]  added. Total players:"+gamePlayers.size());
        //notify other clients
        for (GamePlayer everyplayer : gamePlayers.values()) {
          ChatMessage response = new ChatMessage();
          response.message = player.nick+" is connected.";
          everyplayer.con.sendTCP(response);
        }
        //create tank for player
        
        //send list of other tanks
        UnitList units;
        
      }
    }
  }
  
  public void run(){
    
    int loopCounter= 0; //send
    while (true) {
      
      //handle input
      handleClientRequests();
      
      //update map
      map.process();
      
      //
      if(loopCounter > 100) {
        for (GamePlayer everyplayer : gamePlayers.values()) {
          ChatMessage response = new ChatMessage();
          response.message = "server message chat text";
          everyplayer.con.sendTCP(response);
          loopCounter = 0;
        }
      } else {
        loopCounter++;
      }
      
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        log.error("thread sleep failed",e);
      }
    }
  }
  
  public static void main(String[] args) {
    Tanks2dServer gs = new Tanks2dServer();
    if (gs.init()) {
      gs.run();
    }

  }
  

}



